---
id: lab-linux-intro
slug: /labs/linux
sidebar_position: 1
---

# Введение в Linux

## Введение

### Что потребуется перед началом

- ПК, способный запустить систему виртуализации с виртуальной машиной GNU/Linux.
- Минимум 6 GiB свободного места на жестком диске (под систему и
снапшоты).
- Пакет или установщик системы виртуализации (рекомендуется VirtualBox).
- Загруженный образ дистрибутива (рекомендуется Ubuntu 20.04).

### План и задачи лабораторной

1. Часть 1. Начало работы
   1. Подготовка рабочего окружения
   2. Права, пользователи, `su` и `sudo`
   3. Настройка сети ВМ
   4. Подключение по `ssh`, `ssh-agent`
   5. Установка и работа с `tmux`
   6. Выполнение базовых команд
2. Часть 2. Продвинутая работа с системой
   1. Автоматизируем сбор данных о системе с `bash`
   2. Делаем сбор данных регулярным с `cron`
   3. Пишем свой `systemd`-сервис
   4. Запускаем процесс внутри нового пространства имен
   5. Установка docker и запуск `hello-world`

### Отчет

Отчет в формате `docx`. Обязательное содержимое отчета:

1. Фамилия и инициалы студента, номер группы, номер варианта
2. План и задачи лабораторной работы
3. Краткое описание хода выполнения работы
4. Приложить очищенный вывод `history` выполненных команд

### Что нужно сделать, чтобы сдать лабораторную?

1. Выполнить все действия, представленные в методических указаниях и ознакомиться с материалом
2. Продемонстрировать результаты выполнения преподавателю, быть готовым повторить выполнение части задач из лабораторной по требованию
3. Ответить на контрольные вопросы

## Вступление

Для полного понимания рекомендуется ознакомиться с разделами "Терминология", "Файлы, каталоги, права" и "Работа с системой" [справочных материалов](https://github.com/iu5git/linux-course/blob/master/Wiki.md#суперпользователь-и-смена-пользователей).

## Часть 1. Начало работы

### Задача

Установить любую систему виртуализации, настроить виртуальную машину с любым дистрибутивом GNU/Linux и выполнить набор простейших действий (подробно описан в п. 1.2).

:::info
Если вы не работали с виртуализацией раньше - ставьте VirtualBox. Вопросы различий виртуализации и решения проблем с системами виртуализации выходят за рамки курса.

Если вы не работали раньше с GNU/Linux - ставьте дистрибутив Ubuntu (он используется в методических указаниях). Вопросы различий дистрибутивов и проблем с установкой ПО на разных дистрибутивах выходят за рамки курса.

Лектор любит и всем советует использовать Debian, для более продвинутых есть опция работать по [материалам курса Linux](https://github.com/iu5git/linux-course/blob/master/Lab1.md)

Если вы опытный "линуксоид" - стоит сразу начинать работать по `ssh` (сразу проделав).
:::

### 1.1. Подготовка рабочего окружения

1. Устанавливаем [VirtualBox](https://www.virtualbox.org/wiki/Downloads) или любую другую систему виртуализации.
2. Скачиваем образ для установки дистрибутива Ubuntu 20.04 с [официального сайта](https://releases.ubuntu.com/20.04/). Вы можете выбрать любой способ загрузки, подходящий вам, например через Torrent клиент.

   :::info
   Во время подготовки курса использовался образ `ubuntu-20.04.6-live-server-amd64`, как наиболее универсальный вариант. Но с серверов-зеркал он загружался целую вечность. **Лучше использовать BitTorrent**.
   :::

3. Пока качается образ - создаем виртуальную машину (далее ВМ) в системе виртуализации.

   Ставить будем в VirtualBox (далее VB).

   Как назвать - дело ваше. Удобно набрать "Ubuntu" в названии, тогда VB сразу подставит значения для Ubuntu в выпадающие списки.

   ![image1](./images/image1.jpg)

   Выделяем диск. Использовать рекомендуется динамический виртуальный диск. Тогда покуда внутри ВМ вы не забьете место на диске - оно не будет занято и в вашей хостовой системе. Фактический размер будет динамически растягиваться под требования (но автоматически сжиматься не будет). Достаточно будет и 10 GiB. Лучше сразу больше, все равно место оно не занимает, пока не потребуется.

   ![image2](./images/image2.jpg)

   Получится как-то так:

   ![image3](./images/image3.jpg)

   ![image4](./images/image4.jpg)

4. Идем в настройки VirtualBox и создаем новую сеть NAT. Настраиваем
   проброс портов `127.0.0.1:2222 -> 10.0.2.15:22`.

   ![image5](./images/image5.jpg)

   ![image6](./images/image6.jpg)

5. В настройках ВМ в системе виртуализации выбираем загруженный образ в качестве содержимого оптического носителя, чтобы с него загрузиться:

   ![image7](./images/image7.jpg)

   :::info
   Для систем с большим разрешением экрана советую сразу поставить в "Настройки ВМ" -> "Дисплей" коэффициент масштабирования побольше. На MacBook-ах с Retina-display иначе слишком мелко.
   :::

6. В настройках ВМ в пункте "Сеть" выбираем "Сеть NAT" и нашу новую сеть.

   ![image9](./images/image9.jpg)

7. Запускаем виртуальную машину и устанавливаем систему. Подробно
   рассматривать процесс установки не будем, остановимся только на
   самых важных деталях. [Руководство по установке Ubuntu-Server](https://ubuntu.com/tutorials/install-ubuntu-server).

   :::info
   Для интересующихся руководство по установке Debian для x86-64 архитектуры вы можете найти [тут](https://www.debian.org/releases/stable/amd64/index.ru.html). [Полный список руководств](https://www.debian.org/releases/stable/installmanual).
   :::

   ![image10](./images/image10.jpg)

   Выбор региона и раскладки клавиатуры. Если выбираете себе что-то, кроме английской раскладки - дело ваше, страдать Вам. Я оставляю все по-умолчанию.

   ![image12](./images/image12.jpg)

   Далее настройки сетевого интерфейса. Оставляем по-умолчанию.

   ![image13](./images/image13.jpg)

   Proxy - пропускаем, оставляем пустым.

   ![image16](./images/image16.jpg)

   Какое зеркало для загрузки репозиториев использовать - выбираем `ru.archive.ubuntu.com` - зеркало Yandex.

   ![image17](./images/image17.jpg)

   Настройки разметки диска. Можем оставить по-умолчанию - система автоматически поставится поверх LVM. Для реальных систем идут жаркие споры о том стоит или не стоит ставить систему на LVM. Но у нас требований к надежности нашей виртуальной машины нет, поэтому установим сразу поверх. Из плюсов решения: можно легко расширять доступное под систему место с помощью добавления новых дисков в lvm.

   Из минусов: при потере части этих дисков есть шанс систему больше не запустить.

   ![image20](./images/image20.jpg)

   Но для желающих разобраться разберем добавление нового LV-раздела, выбрали Custom storage layout:

   ![image21](./images/image21.jpg)

   Настройки пользователя, [hostname](https://en.wikipedia.org/wiki/Hostname) - сетевое имя системы и пароля. Пароль [root](https://ru.wikipedia.org/wiki/Root) (пользователя с идентификатором (UID - user ID) 0 и имеющим неограниченные привилегии, аналог администратора, далее будем называть его root) не устанавливается. Задаем пароль только для своего основного пользователя. Настоятельно не советуем ставить свой настоящий сложный пароль на ВМ. После ввода его попросят еще раз для подтверждения, что вы в своем уме.

   ![image23](./images/image23.jpg)

   Выбираем установить OpenSSH-сервер.

   ![image24](./images/image24.jpg)

   Ожидаем завершения установки, перезагружаемся. После выбора пункта Reboot нужно будет зайти в настройки и проверить, что носитель из виртуального дисковода извлечен. После этого перезагружаем ВМ.

   ![image27](./images/image27.jpg)

   ВМ "на логине". Пробуем войти своим пользователем. Если все введено верно, то вы увидите приглашение ввода команд (command prompt), например: `mak@overmind:~$`. Критический успех!

   ![image28](./images/image28.jpg)

8. Делаем мгновенный снимок виртуальной машины, если ваша система виртуализации это поддерживает. Тогда в любой момент мы сможем вернуться на данное состояние системы, если что-то сломаем. В VB переходим во вкладку "Снимки" (Snapshots) и нажимаем "сделать". Названия не принципиальны. Для примера сделали это над другой ВМ (Debian).

   :::info
   Люди делятся на два типа:

   1. Еще не делают бэкапы
   2. Уже делают бэкапы
   :::

   ![image30](./images/image30.jpg)

   ![image32](./images/image32.jpg)

9. Что-нибудь изменим в системе, например напишем пару команд и выключим ВМ. Теперь попробуем восстановить мгновенный снимок из шага 8. Если все в полном порядке, вы откатитесь к состоянию ВМ на момент конца шага 7.

   :::info
   Люди, которые делают бэкапы, делятся на два типа:

   1. Еще не проверяют свои бэкапы после создания
   2. Уже проверяют свои бэкапы после создания
   :::

   ![image33](./images/image33.jpg)

   Снимаем галочку, чтобы не создать снимок текущего (будем считать его испорченным) состояния:

   ![image35](./images/image35.jpg)

   :::info
   Можете добавить в список навыков в выводе отчета, что вы научились делать резервные копии и сразу проверять их на работоспособность. **Очень важный навык для любого DevOps-инженера или администратора.**
   :::

10. Перезагружаемся (reset) с помощью VB. ВМ мгновенно перезапустится (будто мы обесточили и снова запустили сервер). Если все в порядке - вы снова окажетесь "на логине".

    ![image37](./images/image37.jpg)

### 1.2. Права, пользователи, su и sudo

#### Становимся root

Станьте [суперпользователем](https://github.com/iu5git/linux-course/blob/master/Wiki.md#%D1%81%D1%83%D0%BF%D0%B5%D1%80%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C-%D0%B8-%D1%81%D0%BC%D0%B5%D0%BD%D0%B0-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B5%D0%B9) (root-ом) с помощью утилиты `sudo -i`. Так как пароль root не задан - мы пока не можем стать им с помощью `su`.

:::info
**Root** (англ. _root_ — корень; читается "рут"), или **суперпо́льзователь** — это специальный аккаунт и группа пользователей в UNIX-подобных системах с идентификатором UID 0 (User IDentifier), владелец которого имеет право на выполнение всех без исключения операций. Суперпользователь UNIX-систем имеет логин "root" только по умолчанию и легко переименовывается при необходимости, часто встречается переименование в "toor" для усложнения подбора паролей автоматическими сканерами.

**su** (англ. **S**ubstitute **U**ser, **S**et **U**ID, **S**witch **U**ser*, **S**uper **U**ser* — замена пользователя, переключение пользователя, суперпользователь) — команда Unix-подобных операционных систем, позволяющая пользователю войти в систему под другим именем, не завершая текущий сеанс. Обычно используется для временного входа суперпользователем для выполнения административных работ. По умолчанию предполагается работа от имени пользователя root. Если первый аргумент `su` — дефис `-` , среда будет установлена такой же, как при регистрации заданного пользователя. Иначе передается текущая среда, за исключением значения `$PATH`, которое задается переменными `PATH` и `SUPATH` в файле `/etc/default/su`.

**sudo** (англ. **S**ubstitute **U**ser and **do**, дословно "подменить пользователя и выполнить") — программа для системного администрирования UNIX-систем, позволяющая делегировать те или иные привилегированные ресурсы пользователям с ведением протокола работы.

**Основная идея** — дать пользователям как можно меньше прав, но при этом достаточных для решения поставленных задач.
:::

#### Редактируем sudoers

Далее с помощью утилиты `visudo` можно отредактировать файл `/etc/sudoers`(через утилиту - чтобы ничего не сломать, она создает временный файл и перед применением изменений проверяет синтаксис) - разрешить группе `wheel` делать `sudo`с паролем.

:::info
В GNU/Linux CTRL часто обозначается как `^`:

- Сохранить в nano: `^O`.
- Выйти из `nano`: `^X`.
- Поиск по файлу: `^W`.
:::

Этого можно добиться добавив строку `%wheel ALL=(ALL:ALL) ALL`:

- **%wheel** ALL=(ALL:ALL) ALL

  Первое поле показывает имя пользователя или группы, к которым будет применяться правило, в данном случае к группе **wheel**, для пользователя нужно убрать `%`.

- %wheel **ALL=**(ALL:ALL) ALL

  Первое "ALL" означает, что данное правило применяется ко всем хостам.

- %wheel ALL=(**ALL**:ALL) ALL

  Данное "ALL" означает, что пользователь группы **wheel** может запускать команды от лица всех пользователей.

- %wheel ALL=(ALL:**ALL**) ALL

  Данное "ALL" означает, что пользователь группы **wheel** может запускать команды от лица всех групп.

- %wheel ALL=(ALL:ALL) **ALL**

  Последнее "ALL" означает, что данные правила применяются всем командам.

Хорошая статья о sudoers файле [тут](https://www.digitalocean.com/community/tutorials/how-to-edit-the-sudoers-file-ru).

#### Добавим пользователя, группу и изменим права

[Пользователи в Linux](https://github.com/iu5git/linux-course/blob/master/Wiki.md#%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B8-%D0%B2-gnulinux).

1. Создаем пользователя `ansible`с домашней директорией `/home/ansible/`. Например, с помощью утилиты `adduser`. Хорошая [статья](https://andreyex.ru/linux/komandy-linux-i-komandy-shell/useradd-protiv-adduser-v-chem-raznitsa/) о создании пользователей.
2. Меняем пользователю `ansible`пароль с помощью `passwd ansible`.
3. Меняем `root`пароль с помощью `passwd`.
4. Создаем группу wheel с помощью `groupadd wheel`.

    :::caution
    В GNU/Linux нет магии, все происходит максимально логично. Так, добавление пользователя сводится к изменению файлов `/etc/passwd` и `/etc/shadow`. Исторически файл `/etc/passwd` содержал информацию о пользователях и их зашифрованные (чаще всего - хешированные) пароли. Однако, для того,чтобы пользователь мог взаимодействовать с системой - запускать программы от лица других пользователей, просматривать права доступа и так далее, нам необходимо, чтобы этот файл был доступен для чтения всем. А значит, в теории, пароли других пользователей можно было бы подобрать перебором, ведь они нам были бы тоже доступны. Для того, чтобы избежать проблем с утечкой паролей - их вынесли в отдельный файл `/etc/shadow`. Больше о формате этих файлов стоит узнать в справочных материалах.
    :::

    ![image38](./images/image38.jpg)

5. Создать директорию `/admin` c помощью `mkdir /admin`.
6. [Читаем про систему прав](https://github.com/iu5git/linux-course/blob/master/Wiki.md#система-прав-в-gnulinux).
7. Сделать owner-ом директории `/admin` пользователя `ansible` и выдать права группе
    `wheel`:

    ```bash
    chown ansible:wheel /admin
    ```

8. Выдать на права на чтение и редактирование пользовтелю `ansible`,а группе `wheel`
    только не чтение:

    ```bash
    chmod 640 /admin
    ```

#### History

Настроим для root сохранение истории, добавим это в конец `/root/.bashrc`, чтобы история незамедлительно сливалась в файл (а не при завершении сессии):

```bash
shopt -s histappend
PROMPT_COMMAND="history -a;$PROMPT_COMMAND"
```

Аналогичное действие проведите для `.bashrc` вашего пользователя, с помощью которого вы подключаетесь на хост.

Для синхронизации history между сессиями можно добавить в текущий env
(либо также добавить в `.bashrc`, но не советую, т.к. при вводе нескольких команд с разных консолей одновременно - может перетирать историю, которая не успела сохраниться на диск, но если вас не очень заботит мультипоточность можно):

```bash
export PROMPT_COMMAND='history -a;history -c;history -r'
```

**А теперь перестаньте уже быть root, это вредно** - наберите команду `exit` или нажмите комбинацию `^D` (`CTRL+D`).

Демонстрация некоторых командна некотором сервере, просто для ознакомления, не руководство к действию:

![image40](./images/image40.jpg)

### 1.3. Настройка сети ВМ

:::caution
Ubuntu за последние годы сменила уже 3 или 4 сервиса управления сетью, не советую привязываться к текущему - `netplan`.
:::

Смотрим на свои сетевые интерфейсы и списки маршрутов:

```bash
ip a # сокращение от ip address
ip r # сокращение от ip route

# Для любителей старины, стоит знать:
apt install net-tools # ставим пакет старых утилит управления сетью
ifconfig # аналог ip a
route -n # аналог ip r
```

Запомните свой IP и GW:

```bash
$ ip a | grep -v '127.0.0.1' | grep 'inet '
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute enp0s3
$ ip r
default via 10.0.2.1 dev enp0s3 src 10.0.2.15 metric 202
```

IP - `10.0.2.15`
GW - `via 10.0.2.1`

Редактируем настройки:

```bash
sudo nano /etc/netplan/00-installer-config.yaml
```

Содержимое файла должно стать примерно таким (детали зависят от настроек сетевых интерфейсов выше):

```yaml
network:
  ethernets:
    enp0s3:
      dhcp4: no
      addresses: [10.0.2.15/24]
      gateway4: 10.0.2.1
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]
  version: 2
```

Применяем настройки:

```bash
sudo netplan --debug apply
```

### 1.4. Подключение по ssh, ssh-agent

:::info
**SSH** (англ. **S**ecure **Sh**ell — "безопасная оболочка") — сетевой протокол прикладного уровня, позволяющий производить удалённое управление операционной системой и [туннелирование](<https://ru.wikipedia.org/wiki/%D0%A2%D1%83%D0%BD%D0%BD%D0%B5%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_(%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%BD%D1%8B%D0%B5_%D1%81%D0%B5%D1%82%D0%B8)>) TCP-соединений (например, для передачи файлов). Схож по функциональности с более старыми протоколами Telnet и rlogin, но, в отличие от них, шифрует весь трафик, включая и [передаваемые пароли. SSH допускает выбор различных алгоритмов шифрования. [Больше про SSH](https://github.com/iu5git/linux-course/blob/master/Wiki.md#ssh).
:::

:::caution
По-умолчанию ssh-сервер использует 22-ой TCP-порт.
:::

1. Установить на **основную систему** (ее еще называют хостовой или гипервизором) ssh-клиент. В Unix/Linux системах `ssh`стоит по-умолчанию. В Windows - [PuTTY](https://www.putty.org/), проще всего скачать установщик всех утилит (сам PuTTY, PuTTYgen, pageant и прочие программы).

2. **Мы уже сделали это в пункте 1.1**. Но покажу еще один вариант как настроить "проброс портов" (port-forwarding) для виртуальной машины `127.0.0.1:2222 -> 10.0.2.15:22`.

   :::info
   Зачем это нужно? Мы используем NAT, соответственно нам нужно направить пакеты за NAT в нашу виртуальную сеть. Рассматривайте это как конфигурирование настроек роутера, для доступа к вам в локальную сеть из интернета.
   :::

   ![image41](./images/image41.jpg)

   ![image42](./images/image42.jpg)

3. На ВМ-установить и запустить `sshd` (проверить запущен ли: `systemctl status sshd`, запустить: `systemctl start sshd`).

4. На **основной** системе настроить ssh-подключение по ключу

   :::info
   Подробная статья о PuTTY есть на [хабре](https://habr.com/ru/post/127521/).
   :::

   Сгенерировать ssh-ключи (в утилите [PuTTYgen](https://www.ssh.com/academy/ssh/putty/windows/puttygen) или `ssh-keygen`). Для этого нужно перегенерировать ключ 2 версии.

   Windows:

   ![image44](./images/image44.jpg)

   ![image45](./images/image45.jpg)

   Unix/Linux:

   ![image46](./images/image46.jpg)

   Положить публичную часть ключа в файл `/home/ansible/.ssh/authorized_keys` на **ВМ**.

   Для простоты можно скопировать публичную часть ключа из окна генератора в notepad, а потом сразу забросить на сервер руками - подключитесь с помощью PuTTY, откройте текстовый редактор на редактирование нужного файла и скопируйте из notepad в окно терминала ключ.

   Да, директории `.ssh`может еще не существовать, создайте. Права установите в `rwx------`.

   :::caution
   Вам нужна публичная часть ключа в формате однострочной записи:

   ```bash
   <type> <key> <optional-comment> .
   ```

   Пример:

   ```bash
   ssh-rsa
   XXXXXXXXXXc2EAAAADAXABAAABAXC5Am7+fGZ+5zXBGgXS6GUvmsXCLGc7tX7/rViXk3+eShZzaXnt75gUmT1I2f75zFn2hlAIDGKWf4g12KWcZxy81TniUOTjUsVlwPymXUXxESL/UfJKfbdstBhTOdy5EG9rYWA0K43SJmwPhH28BpoLfXXXXXG+/ilsXXXXXKgRLiJ2W19MzXHp8z3Lxw7r9wx3HaVlP4XiFv9U4hGcp8RMI1MP1nNesFlOBpG4pV2bJRBTXNXeY4l6F8WZ3C4kuf8XxOo08mXaTpvZ3T1841altmNTZCcPkXuMrBjYSJbA8npoXAXNwiivyoe3X2KMXXXXXdXXXXXXXXXXCXXXXX/ user@myserver
   ```

   PyTTY сохраняет `.pub/.pem` файл в формате PKCS8. Для конвертации на Linux можно воспользоваться утилитой `ssh-keygen -i -m PKCS8 -f public-key`

   Проверить права файла `/home/ansible/.ssh/authorized_keys`, они должны быть `rw-r--r--`.

5. Продемонстрировать подключение по ssh (PuTTY+pageant для windows) под пользователем `ansible` и стать root-ом с помощью `sudo`. Подключаться на проброс портов: `<your_user>@127.0.0.1:2222.`.

   Windows:

   ![image48](./images/image48.jpg)

   ![image49](./images/image49.jpg)

   ![image50](./images/image50.jpg)

   Unix/Linux, сразу с применением `ssh-copy-id` вместо ручного редактирования `authorized_keys`:

   ![image51](./images/image51.jpg)

### 1.5. Установка и работа с tmux

Мы уже сталкивались с установкой пакетов. Рассмотрим подробнее, в Ubuntu для этого используется пакетный менеджер `apt`. Подробнее [тут](https://github.com/iu5git/linux-course/blob/master/Wiki.md#%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0-%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%BF%D0%B0%D0%BA%D0%B5%D1%82%D0%B0%D0%BC%D0%B8).

```bash
sudo apt install tmux
```

**Tmux** - терминальный мультиплексор. Очень удобная штука для работы с несколькими сессиями в системе (или несколькими системами). Позволяет открывать и поддерживать на сервере несколько сессий. Что гарантирует защиту от внезапного завершения процессов в вашей консоли при разрыве соединения без использования `nohup`. Статья [тут](https://habr.com/ru/post/327630/).

![image54](./images/image54.jpg)

Теперь запускаем сессию с идентификатором по-умолчанию (для первой - `0`):

```bash
tmux
```

Создадим пару новых окон несколько раз нажав: `^B` + `C`.

Переключимся между ними с помощью `^B` + `W` . Переключаться между двумя последними можно `^B` + `L`, переключиться на конкретное окно по его номеру, например первое, так: `^B` +`0`.

Далее работать будем так. Если нужно отключиться без завершения сессий набираем `^B` + `D`.

Закрыть окно можно с помощью `^B`+ `C`- так мы перейдем в командный режим (ввод команд tmux-у в поле ввода внизу),затем вводим `kill-window` и нажимаем `enter`.

Для повторного подключения к нужной сессии `tmux a -t $ID`:

```bash
tmux a -t 0
```

### 1.6. Выполнение базовых команд

#### Шпаргалка наиболее частых команд

- `cd` (change directory) - сменить рабочий каталог
- `mv` (move) - переместить объект фс
- `cp` (copy) - скопировать объект фс
- `mkdir` (make directory) - создать каталог
- `echo` - вывод аргументов на экран
- `cat` - вывод объекта (например, файла) на экран
- `less` - утилита для удобного просмотра больших текстовых файлов
- `sort` - утилита для сортировки
- `grep` - фильтрация строк по подстрокам

:::info
Статья о циклах в командной оболочке [тут](https://losst.pro/tsikly-bash).
:::

Разберем несколько:

- `ls` — покажет содержимое директории, в которой вы находитесь. Если после команды ввести адрес конкретной папки, то она покажет то, что хранится в ней. [Типы файлов](https://github.com/iu5git/linux-course/blob/master/Wiki.md#типы-файлов-в-gnulinux). [Система прав](https://github.com/iu5git/linux-course/blob/master/Wiki.md#типы-файлов-в-gnulinux). Полезные аргументы:

  - `-R` в выводе команды появятся файлы из поддиректорий
  - `-l` отобразить списком с метаданными (права доступа и прочая информация из inode)
  - `-a` отобразить скрытые (начинающиеся с точки) объекты

- `cd` — change directory, сменить директорию. Из названия понятно, что с помощью этой команды можно перемещаться между каталогами. Вписываем её, а потом путь, например: `cd /path/to/dir` .

  Есть сокращенные варианты:

  - `cd -` для перемещения в предыдущую директорию
  - `cd` (без аргументов) для прыжка в домашнюю папку

- `cp` - copy - скопировать объект. Из полезных опций `-r` позволяет делать рекурсивно (для всех подкаталогов) и `-p` позволяет сохранить все права на файл как у исходного.
- `pwd` — укажет полный путь до директории, в которой вы находитесь. Если вы перепрыгнули на рабочий стол с помощью cd `~/Desktop/`, то `pwd` покажет что-то вроде `/home/mak/Desktop`.
- `rm` — команда для удаления файлов, каталогов и их содержимого. Удаляет жесткие ссылки,фактически данные остаются на диске, просто мы теряем на них указатели и эти блоки данных теперь считаются пустыми. На форумах часто ходит злая шутка для новичков, которым советуют починить что-нибудь в их систему с помощью `rm -rf /`, что потенциально стирает все данные.

  Полезные аргументы:

  - `-r` удалить каталог и все вложенные объекты
  - `-f` удалить без подтверждения

- `grep` — это полнотекстовый поиск в файле. Очень полезная команда, когда вам нужно что-то найти. Например, `grep` значение `/путь/до/файла` покажет строки в которых есть "значение". А команда `grep -ril` значение `/путь/до/каталога/*` покажет все файлы, в которых есть искомое значение.

  Полезные аргументы:

  - `-r` рекурсивный поиск
  - `-i` игнорировать регистр (case **i**nsensetive)
  - `-l` вывести результат списком
  - `-v` инвертировать работу - пропускать только строки, в которых **НЕТ** значения
  - `-E` использовать регулярные выражения в "значении"

- `df` — disk free - показывает данные по ФС, в т.ч. сколько еще свободно места на каких ФС.

  - `-h` human-friendly, переводит байты в читаемое
  - `-i` inode, показывает информацию по айнодам на ФС

- `du` — disk usage - показывает данные по всем неудаленным файлам на ФС.

  - `-h` human-friendly, переводит байты в читаемое

- `chown пользователь:группа` путь — команда позволяет изменить владельца файла или каталога. `-R` для рекурсивного.
- `chmod права путь` — изменяет права на файл или каталог. Подробнее в разделе "Система прав в GNU/Linux".
- `find` — с помощью этой утилиты можно искать (и даже удалять) файлы по определённым параметрам. Например: `find /mnt/data/backup/ -mtime +3 -type f -iname "*.sql.gz"` - выведет все файлы (`-type f`) в директории `/mnt/data/backup` 3-х дневной давности (дата изменения `modify time +3 - -mtime +3`) с именем попадающим в маску `*sql.gz`. При добавлении опции `-delete` удаляет найденные файлы. Часто используется в таком виде в скриптах для очистки старых логов или резервных копий.
- `awk` — си-подобный сценарный язык построчного разбора и обработки входного потока по заданным шаблонам. Ключей много. Примеры и статья на хабре:`echo word1 word2 word3 word4 | awk '{ print $2,$4 }'` выведет `word2 word4` для каждой строки (тут всего одна). `echo word1:word2:word3:word4 | awk -F: '{ print $1,$3 }'` выведет `word1 word3`.
- `tail` — позволяет вывести только конец файла/потока.

  - `+2` - выкинуть первую строку
  - `-n X` - оставить только `Х` последних строк

- `head` — аналогично `tail`, только для начала файла/потока.
- `ps` — посмотреть список процессов, с аргументом aux показывает все процессы в системе.

#### Pipeline

Для выполнения работы вам непременно потребуется знание о том, что такое конвейер (pipeline). Небольшое напоминание о работе конвейера:

```bash
cat file.txt | grep bmstu | sort -u
```

- `cat file.txt` - вывести содержимое файла, передаем это утилите `grep`
- `grep bmstu` - оставить только строки, содержащие `bmstu`, передать вывод утилите `sort`
- `sort -u` - отсортировать в алфавитном порядке и оставить только уникальные значения

#### Shell/Bash

Пример скрипта, который создает файл с содержимым первого и второго аргументов:

```bash
#!/bin/sh

echo "$1" > test.txt
echo "$2" >> test.txt
```

Пример того, как сделать файл "исполняемым":

```bash
chmod +x file.sh
```

Пример того, как запустить "исполняемый" файл c аргументами из текущей директории:

```bash
./file.sh 10 15
```

:::info
А почему исполняемый файл нельзя запустить просто написав file.sh как в windows?

Все дело в безопасности. Это очень плохая идея позволять подменять стандартные утилиты файлами из текущей директории, есть риск исполнить не то, что подразумевал пользователь, а то, что подложил ему в каталог злоумышленник. Поэтому текущая директория **не добавляется** к переменной `PATH`, списку директорий в которых производится поиск исполняемых файлов.
:::

#### Man

Продемонстрировать умение пользоваться утилитой [man](https://ru.wikipedia.org/wiki/Man). Вывести страницу мануала для утилиты `apt`.

:::info
Демонстрация проделанной работы происходит через вывод утилиты `history`.
:::

## Часть 2. Продвинутая работа с системой

Основная задача: научиться управлять процессами и создавать простейшую автоматизацию.

### 2.1. Автоматизируем сбор данных о системе с bash

1. Выведем LA:

   ```bash
   cat /proc/loadavg | awk '{ print $1,$2,$3" processes: "$4", last PID: "$5}'
   ```

   **LA, Load average** - среднее значение загрузки системы за некоторый период времени, как правило, отображается в виде трёх значений, которые представляют собой усредненные сглаженные величины за последние 1, 5 и 15 минут. Вычисляется как длина очереди выполнения в операционной системе, где единица означает, что очередь заполнена, а значение выше единицы — что есть процессы, которые ожидают своей очереди на выполнение. Содержатся в файле `/proc/loadavg`.

   Учитывает как running процессы, так и процессы в `uninterraprable sleep` (ожидают выполнения системного вызова, как правило долгие это read/write, т.е. IO).

2. Выведем список сетевых интерфейсов в нужном формате

   ```bash
   ss -4tuln | подставьте что нужно, можно цепочку из нескольких команд | column -t
   ```

   ```bash
   127.0.0.53%lo  53
   127.0.0.53%lo  53
   0.0.0.0        22
   ```

3. Выведем список IP-адресов на хосте:

   ```bash
   ip a | grep -E 'inet ' | awk '{ print $2 }'
   ```

4. Обернем это все в bash-скрипт `/root/beholder.sh`, добавим `date + "%d.%m.%Y %H:%M:%S"` и информацию о занятом месте и списке пользователей (самостоятельно). Попробуем циклы, запишем в скрипт:

   ```bash
   for i in $@
   do
       echo "Next search by name:"
       ps aux | grep $i
       echo
   done
   ```

5. Запустим. Должны получить что-то вроде:

   ![beholder](./images/beholder.png)

### 2.2. Делаем сбор данных регулярным с cron

1. Впишем в cron новое правило и ждем минуту.

   ```bash
   echo '* * * * * root /root/beholder.sh >> /tmp/beholder-output' >
   /etc/cron.d/beholder
   ```

2. Смотрим файл `cat /tmp/beholder-output`

   Можем попробовать поменять параметры, сервис [crontab.guru](https://crontab.guru/) в помощь.

   Краткое описание есть в файле конфига `/etc/crontab`:

   ![image57](./images/image57.jpg)

   Исходя из этого конфига следует, что в `/etc/cron.{hourly,daily, weekly,monthly}/` лежат скрипты, запускающиеся соответственно раз в день, в неделю и в месяц. Дополнительно Cron читает конфиги из `/etc/cron.d/`, где лежат общие файлы с расписанием запуска.
   Кроме того, для пользователей задаются персональные cron-конфиги. Их можно отредактировать с помощью утилиты `crontab -e`. Они отличаются от `/etc/crontab` тем, что там опускается поле пользователя, запускаться будет от того, который себе задал это в настройках.

### 2.3. Пишем свой systemd-сервис

Процесс не может взяться из ниоткуда: его обязательно должен запустить какой-то процесс. Процесс, запущенный другим процессом, называется дочерним (child) процессом или потомком. Процесс, который запустил процесс называется родительским (parent), родителем или просто - предком. У каждого процесса есть два атрибута - **PID** (Process ID) - идентификатор процесса и **PPID** (Parent Process ID) - идентификатор родительского процесса.

Процессы создают иерархию в виде дерева. Самым "главным" предком, то есть процессом, стоящим на вершине этого дерева, является процесс `systemd` или `init` (`PID = 1`). Условно можно считать, что планировщик ядра имеет `PID = 0`.

Собственно для управления древом процессов и создали `systemd`. Подробнее о процесса и их состояниях читайте в [статье](https://github.com/iu5git/linux-course/blob/master/Wiki.md#%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81-%D0%B2-gnulinux).

[systemd](https://ru.wikipedia.org/wiki/Systemd) — подсистема инициализации и управления службами в GNU/Linux, фактически вытеснившая в 2010-е годы традиционную подсистему [init](https://ru.wikipedia.org/wiki/Init). Основная особенность — интенсивное распараллеливание запуска служб в процессе загрузки системы, что позволяет существенно ускорить запуск операционной системы. Основная единица управления — unit (модуль), одним из типов модулей являются "сервисы" — аналог демонов — наборы процессов, запускаемые и управляемые средствами подсистемы и изолируемые [контрольными группами](https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%82%D1%80%D0%BE%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%B3%D1%80%D1%83%D0%BF%D0%BF%D0%B0_(Linux)). Подробная [статья](https://linux-notes.org/pishem-systemd-unit-fajl/) об systemd-unit-ах.

Создадим свой systemd-unit:

```bash
nano /etc/systemd/system/myhttp.service

# Создадим для него WorkingDirectory
mkdir -p /root/www

# Перезагрузим конфигурацию
systemd systemctl daemon-reload
```

Содержимое `.service` файла:

```bash
[Unit]
Description=MyHTTP Server
Documentation=http://example.org/
After=network.target

[Service]
WorkingDirectory=/root/www
ExecStart=/usr/bin/python3 -m http.server 8000
KillMode=mixed
Restart=on-failure
Type=simple

[Install]
WantedBy=multi-user.target
Alias=myhttpd.service
```

Кратко разберем что тут написано:

- Секция `[Unit]`:

  - `Description` - описание, отображается в `systemctl status [service]`
  - `Documentation` - ссылка на документацию, обязательно в виде URL
  - `After` - после каких целей/сервисов следует запускать данный unit

- Секция `[Service]`:

  - `WorkingDirectory` - вызовет системный вызов `chdir` перед исполнением каких-либо команд сервиса, должна существовать
  - `ExecStart` - команда, которая запустится при вызове `systemctl start [service]`
  - `KillMode` - управляет тем, как процесс должен быть завершен, `mixed` - посылает `SIGTERM` основному процессу и `SIGKILL` дочерним
  - `Restart` - необходимо ли перезапускатьсервис в случае завершения процесса (в примере - только при ненулевом rc)
  - `Type` - настраивает процедуру запуска и отслеживания процесса, `simple` ожидает, что основным станет процесс, запущенный ExecStart командой и сервис будет работать до тех пор, пока жив основной процесс.

- Секция `[Install]`:

  - `WantedBy` - какая цель триггерит запуск, если сервис `enabled`.
  - `Alias` - альтернативное имя сервиса. `systemctl status [alias]` равнозначен `systemctl start [service]`.

Запустим, добавим в автозапуск:

```bash
systemctl start myhttp
systemctl enable myhttp
```

Проверяем работу с помощью `curl` и `ss`.

```bash
curl http://127.0.0.1:8000/
ss -tl | grep 8000
```

:::info
Для ответа на контрольный вопрос про процесс загрузки системы
также нужно ознакомиться с [материалом](https://github.com/iu5git/linux-course/blob/master/Wiki.md#%D0%BF%D1%80%D0%BE%D1%86%D0%B5%D1%81%D1%81-%D0%B7%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BA%D0%B8-gnulinux).
:::

### 2.4. Запускаем процесс внутри нового пространства имен

Посмотрим список доступных пространств имен:

```bash
lsns
ip netns
```

Цикл [статей](https://habr.com/ru/post/458462/) на Habr про пространства имен.

Создаем сетевой namespace:

```bash
ip netns add myhttp
```

Теперь запустим внутри пару команд `ip netns exec <netns> <cmd> ...`:

```bash
ip netns exec myhttp ip link set dev lo up
ip netns exec myhttp /usr/bin/python3 -m http.server 8080 &
```

Проверим:

```bash
ss -tul4n
ip netns exec myhttp ss -tul4n
```

Запустим tcpdump внутри netns-а:

```bash
ip netns exec myhttp tcpdump -i any host 127.0.0.1
```

Проверим:

```bash
ip netns exec myhttp curl http://127.0.0.1:8080
ip netns exec myhttp curl http://127.0.0.1:8000
curl http://127.0.0.1:8080
curl http://127.0.0.1:8000
```

Таким образом, у нас получилось разнести 2 разных сервера в разные сетевые пространства имен. Мы даже можем запустить их на одинаковом порту.

### 2.5. Установка docker и запуск hello-world

[Установка Docker в Ubuntu 20.04](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-ubuntu-20-04-ru)

```bash
sudo apt install apt-transport-https ca-certificates curl software-properties-
common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64]
https://download.docker.com/linux/ubuntu focal stable"
sudo apt update
sudo apt install docker-ce
sudo systemctl status docker
```

Запустим [hello-world](https://hub.docker.com/_/hello-world):

```bash
docker run hello-world
```

### 2.6. Дополнительное

1. Показать soft-лимиты (`ulimit`) и hard-лимиты, пояснить как поняли, в чем разница, как изменить?

   Хорошая [статья](https://andreyex.ru/linux/komandy-linux-i-komandy-shell/upravlenie-resursami-sistemy-s-pomoshhyu-komandy-ulimit/) о лимитах.

   :::info
   Примечание: это может оказаться жизненно важным знанием в случае появления высоких нагрузок на вашем сервере. Ошибка "Too Many Open Files" может появляться как раз из-за ограничений в лимитах, по-умолчанию они довольно небольшие (1024 для open files).
   :::

   Пример вывода `ulimit` для пары систем (ВМ и реальный Raspberry-Pi сервер):

   ![image59](./images/image59.jpg)

   Посмотрим лимиты для конкретного процесса, тоже бывает полезно:

   ```bash
   # Некоторые программы кладут свой Process ID (PID) в /var/run
   cat /var/run/sshd.pid # Выведет PID sshd

   # Выведем лимиты процесса sshd с помощью procfs
   cat /proc/$(cat /var/run/sshd.pid)/limits
   # P.S. Про procfs подробно поговорим во второй лабораторной работе
   ```

   ![image60](./images/image60.jpg)

   Занятное наблюдение работы лимитов:

   ![image62](./images/image62.jpg)

2. Настроить `/root/.bashrc` файл, применяющийся при создании новой оболочки для root пользователя.

   Хорошая [статья](https://evilinside.ru/razbiraemsya-s-fajlami-etc-profile-i-etc-bashrc/) о `bash_profile` и `bashrc`.

   [Пример](https://www.opennet.ru/docs/RUS/bash_scripting_guide/a15124.html) большого и сложного `.bashrc` файла.

   PS1 - переменная для изменения вида приглашения, например такое значение красит в красный:

   ```bash
   PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\
   [\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w \$\[\033[00m\] '
   ```

   Синонимы (alias-ы) для подкрашивания вывода команд:

   ```bash
   # enable color support of ls and also add handy aliases
   if [ -x /usr/bin/dircolors ]; then
       test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval
   "$(dircolors -b)"
       alias ls='ls --color=auto'
       alias dir='dir --color=auto'
       alias vdir='vdir --color=auto'
       alias grep='grep --color=auto'
       alias fgrep='fgrep --color=auto'
       alias egrep='egrep --color=auto'
   fi
   ```

   Просто удобные общепринятые сокращения:

   ```bash
   # some more ls aliases
   alias ll='ls -l'
   alias la='ls -A'
   alias l='ls -lA'
   ```

   Переопределения стандартных команд с ключами, чтобы спрашивали подтверждение:

   ```bash
   # Some more alias to avoid making mistakes:
   alias rm='rm -i'
   alias cp='cp -i'
   alias mv='mv -i'
   ```

   ![image64](./images/image64.jpg)

   ![image65](./images/image65.jpg)

3. Создайте еще один мгновенный снимок ВМ, как в пункте 8 раздела 1.1. Чтобы не случалось _"упс, у меня все работало, а вот сейчас перестало"_.

**Далее в лабораторных рекомендуется использовать способ работы с
системой по ssh и запускать ВМ в фоновом режиме (без интерфейса
вообще)**.

## Дополнительные ссылки

1. [Авторизация на базе ключей SSH | selectel](https://selectel.ru/blog/ssh-authentication/)

## Контрольные вопросы

1. Что такое Linux?
2. Что делает каждая из команд, применяемых в лабораторной работе?
3. В чем разница между su и sudo?
4. Что происходит в подробностях, когда вы вводите `cat
file.txt`?
5. Что такое файловый дескриптор? Какие создаются по умолчанию?
6. Как дописать в файл вывод команды? Как перезаписать файл? Как
   избавиться от вывода ошибок?
7. Как определяются права на файл? Как сделать файл исполняемым?
8. Как создать пользователя в GNU/Linux?
9. Как пользоваться man?
10. Как выдать права на sudo?
11. Зачем .bashrc файл?
12. Как посмотреть занятое место на диске?
13. Как подключиться к серверу по ssh? Подробно о всех возможных
    проблемах.
14. Что такое публичный и приватный ключ? Какой оставляем себе, а какой
    копируем на сервер?
15. ssh-agent - зачем?
16. В чем разница между soft и hard лимитами?
17. Кто такой суперпользователь и что ему можно?
18. Нужно ли делать резервные копии? А что еще нужно делать?
19. Что такое systemd, как происходит загрузка системы?
20. Как поставить пакет? Что такое apt?

:::info
Для выбора вопроса можно использовать игральную кость d20
:::
